package com.mgy.example.utils;

import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.*;

/**
 * 解析参数
 * @author mgy
 */
public class ParameterUtil {

    private static void check(String[] paramNames, Class[] paramTypes, Object[] paramValues) {
        Assert.isTrue(paramNames.length == paramTypes.length && paramNames.length == paramValues.length, "参数名称，参数类型，参数值不对应");
    }

    /**
     * 获取对象中指定字段的值
     *
     * @param obj       对象
     * @param type      对象类型
     * @param fieldName 字段名称
     * @return 字段值
     */
    private static <T> T getFieldValue(Object obj, Class type, String fieldName) throws IllegalAccessException {
        Field[] fields = type.getDeclaredFields();
        for (Field field : fields) {
            if (BeanUtils.isSimpleValueType(field.getType())) {
                if (StringUtils.equals(field.getName(), fieldName)) {
                    field.setAccessible(true);
                    return (T) field.get(obj);
                }
            } else {
                return resolve(field.getName(), field.getType(), field.get(obj), fieldName);
            }
        }
        if (type.getSuperclass() != null) {
            return getFieldValue(obj, type.getSuperclass(), fieldName);
        }
        return null;
    }


    /**
     * 从一个参数中查询某个字段的值，
     * 查到一个符号条件的就不再往后查
     *
     * @param paramName       参数名称
     * @param paramType       参数类型
     * @param paramValue      参数对象
     * @param searchFieldName 要查询的字段名称
     * @return 查询的字段值
     */
    public static <T> T resolve(String paramName, Class paramType, Object paramValue, String searchFieldName) throws IllegalAccessException {
        if (paramValue == null) {
            return null;
        }
        if (paramType == null) {
            paramType = paramValue.getClass();
        }
        if (BeanUtils.isSimpleValueType(paramType)) {
            if (StringUtils.equals(paramName, searchFieldName)) {
                return (T) paramValue;
            }
        } else if (paramType.isArray()) {
            int length = Array.getLength(paramValue);
            for (int i = 0; i < length; i++) {
                Object itemObj = Array.get(paramValue, i);
                if (itemObj != null && !BeanUtils.isSimpleValueType(itemObj.getClass())) {
                    return resolve(null, itemObj.getClass(), itemObj, searchFieldName);
                }
            }
        } else if (paramValue instanceof Collection) {
            Collection collection = (Collection) paramValue;
            Iterator iterator = collection.iterator();
            while (iterator.hasNext()) {
                Object itemObj = iterator.next();
                if (itemObj != null && !BeanUtils.isSimpleValueType(itemObj.getClass())) {
                    return resolve(null, itemObj.getClass(), itemObj, searchFieldName);
                }
            }
        } else if (paramValue instanceof Map) {
            Map map = (Map) paramValue;
            Set<Map.Entry> set = map.entrySet();
            for (Map.Entry entry : set) {
                Object key = entry.getKey();
                Object value = entry.getValue();
                if (key != null) {
                    if (BeanUtils.isSimpleValueType(key.getClass()) && key instanceof String && StringUtils.equals(key.toString(), searchFieldName)) {
                        if (value == null) {
                            return null;
                        } else if (BeanUtils.isSimpleValueType(value.getClass())) {
                            return (T) value;
                        }
                    } else if (!BeanUtils.isSimpleValueType(key.getClass())) {
                        return resolve(null, key.getClass(), key, searchFieldName);
                    }
                }
                if (value != null && !BeanUtils.isSimpleValueType(value.getClass())) {
                    return resolve(null, value.getClass(), value, searchFieldName);
                }
            }
        } else {
            return getFieldValue(paramValue, paramType, searchFieldName);
        }
        return null;
    }

    public static <T> T resolve(String[] paramNameArr, Class[] paramTypeArr, Object[] paramValueArr, String searchFieldName) throws IllegalAccessException {
        if (StringUtils.isBlank(searchFieldName) || paramNameArr == null || paramTypeArr == null || paramValueArr == null) {
            return null;
        }
        check(paramNameArr, paramTypeArr, paramValueArr);

        for (int i = 0; i < paramNameArr.length; i++) {
            String paramName = paramNameArr[i];
            Class paramType = paramTypeArr[i];
            Object paramValue = paramValueArr[i];
            return resolve(paramName, paramType, paramValue, searchFieldName);
        }
        return null;
    }
}
